package com.zhou.system.management.security.session;

import com.zhou.common.lib.model.Response;
import com.zhou.common.lib.util.JSONUtils;
import com.zhou.common.lib.util.StringUtils;
import com.zhou.common.operator.log.core.constant.OperateActionEnum;
import com.zhou.common.operator.log.core.model.ClientInfo;
import com.zhou.common.operator.log.core.model.OperateLogInfo;
import com.zhou.common.operator.log.core.model.PrincipalInfo;
import com.zhou.common.operator.log.core.service.OperateLogStorageService;
import com.zhou.system.management.security.model.MyUserDetails;
import com.zhou.system.management.util.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Date;

/**
 * Security Session 过期 Handler
 *
 * tomcat 循环处理过期的session
 * org.apache.catalina.session.StandardSession expire(boolean notify)
 *
 * <p>
 * @serial 2.0.0
 * @author 就眠儀式
 */
@Slf4j
@Component
public class SecureSessionExpiredHandler implements SessionInformationExpiredStrategy {

    @Resource
    private OperateLogStorageService logService;

    @Autowired
    private WebApplicationContext applicationContext;

    @Override
    public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException {
        //超过最大登录数量，被踢下线了
        HttpSession session = event.getRequest().getSession(false);
        if (session != null) {
            if (!isTimeout(session)) {
                //todo 是多人登录被挤下线的
                log.info("超过最大登录数量，被踢下线了");
                //记录被踢下线的日志
                MyUserDetails currentUser = (MyUserDetails) event.getSessionInformation().getPrincipal();
                OperateLogInfo logInfo = new OperateLogInfo();
                logInfo.setAddTime(new Date());
                logInfo.setClientInfo(new ClientInfo());
                PrincipalInfo principalInfo = new PrincipalInfo();
                principalInfo.setUserId(currentUser.getUserId() + "");
                principalInfo.setUserName(currentUser.getUsername());
                principalInfo.setUserPhone(currentUser.getPhone());
                principalInfo.setOrgId(currentUser.getCurrOrgId() + "");
                principalInfo.setOrgName(currentUser.getCurrOrgName() + "");
                logInfo.setPrincipal(principalInfo);
                logInfo.setAction(OperateActionEnum.LOGIN.getAction());
                logInfo.setOperatingInstruction(
                        StringUtils.format("登出成功:超过并发数量被踢出(登录的sessionId={})"
                                , event.getSessionInformation().getSessionId()));
                this.logService.append(logInfo);
                ServletUtil.write(JSONUtils.toJson(Response.error(402, "超过最大登录数量，被踢下线了")));
            } else {
                //todo 是超时了，可以不做处理,HttpSessionListener 会做超时处理
                ServletUtil.write(JSONUtils.toJson(Response.error(402, "session过期，请重新登录")));
            }
            session.invalidate();
        } else {
            log.info(" SecureSessionExpiredHandler session is null ");
        }

    }

    private boolean isTimeout(HttpSession httpSession) {
        int maxInactiveInterval = httpSession.getMaxInactiveInterval();
        long timeNow = System.currentTimeMillis();
        long idleTimeInternal = timeNow - httpSession.getLastAccessedTime();
        if (maxInactiveInterval > 0) {
            int timeIdle = (int) (idleTimeInternal / 1000L);
            if (timeIdle >= maxInactiveInterval) {
                return true;
            }
        }
        return false;
    }
}
